﻿namespace ClassyBlog
{
    using System.Diagnostics;
    using System;
    using System.Collections.Generic;

    using AutoPoco;
    using AutoPoco.DataSources;
    using AutoPoco.Engine;

    using DomainObjects;

    internal static class ObjectMother
    {
        [DebuggerStepThrough]
        public static Blog CreateBlog()
        {
            return CreateBlogSession().Single<Blog>().Get();
        }

        [DebuggerStepThrough]
        public static Tag CreateTag()
        {
            return CreateTagSession().Single<Tag>().Get();
        }

        [DebuggerStepThrough]
        public static IEnumerable<Tag> CreateTags(int count = 4)
        {
            return CreateTagSession().List<Tag>(count).Get();
        }

        [DebuggerStepThrough]
        public static Category CreateCategory()
        {
            return CreateCategorySession().Single<Category>().Get();
        }

        [DebuggerStepThrough]
        public static IEnumerable<Category> CreateCategories(int count = 4)
        {
            return CreateCategorySession().List<Category>(count).Get();
        }

        [DebuggerStepThrough]
        public static Post CreatePost()
        {
            return CreatePostSession().Single<Post>().Get();
        }

        [DebuggerStepThrough]
        public static Page CreatePage()
        {
            return CreatePageSession().Single<Page>().Get();
        }

        [DebuggerStepThrough]
        public static IEnumerable<Page> CreatePages(int count = 5)
        {
            return CreatePageSession().List<Page>(count).Get();
        }

        [DebuggerStepThrough]
        public static IEnumerable<Post> CreatePosts(int count = 5)
        {
            return CreatePostSession().List<Post>(count).Get();
        }

        private static IGenerationSession CreateBlogSession()
        {
            return AutoPocoContainer.Configure(x =>
                x.AddFromAssemblyContainingType<Blog>()
                 .Include<Blog>()
                 .Setup(b => b.Title).Use<RandomStringSource>(4, 256)
                 .Setup(b => b.Tagline).Use<RandomStringSource>(4, 256)
                 .Setup(b => b.MetaKeywords).Use<RandomStringSource>(4, 512)
                 .Setup(b => b.MetaDescription).Use<RandomStringSource>(4, 512)
                 .Setup(b => b.Author).Use<RandomStringSource>(4, 64)
                 .Setup(b => b.Email).Use<EmailAddressSource>()
                 .Setup(b => b.PostsPerPage).Value(5)
                 .Setup(b => b.PagesPerPage).Value(5)
                 .Setup(b => b.Theme).Use<RandomStringSource>(4, 12))
                 .CreateSession();
        }

        private static IGenerationSession CreateTagSession()
        {
            return AutoPocoContainer.Configure(x =>
                x.AddFromAssemblyContainingType<Tag>()
                 .Include<Tag>()
                 .Setup(t => t.Title).Use<RandomStringSource>(4, 32)
                 .Setup(t => t.Slug).Use<RandomStringSource>(4, 32))
                 .CreateSession();
        }

        private static IGenerationSession CreateCategorySession()
        {
            return AutoPocoContainer.Configure(x =>
                x.AddFromAssemblyContainingType<Category>()
                 .Include<Category>()
                 .Setup(c => c.Title).Use<RandomStringSource>(4, 32)
                 .Setup(c => c.Slug).Use<RandomStringSource>(4, 32))
                 .CreateSession();
        }

        private static IGenerationSession CreatePostSession()
        {
            return AutoPocoContainer.Configure(x =>
                x.AddFromAssemblyContainingType<Post>()
                 .Include<Post>()
                 .Setup(p => p.Title).Use<RandomStringSource>(4, 128)
                 .Setup(p => p.PublishedAt).Use<RandomPastDateSource>()
                 .Setup(p => p.Slug).Use<RandomStringSource>(4, 128)
                 .Setup(b => b.MetaKeywords).Use<RandomStringSource>(4, 128)
                 .Setup(b => b.MetaDescription).Use<RandomStringSource>(4, 128)
                 .Setup(b => b.Author).Use<RandomStringSource>(4, 64)
                 .Setup(b => b.Body).Use<LoremIpsumSource>(5))
                 .CreateSession();
        }

        private static IGenerationSession CreatePageSession()
        {
            return AutoPocoContainer.Configure(x =>
                x.AddFromAssemblyContainingType<Page>()
                 .Include<Page>()
                 .Setup(p => p.Title).Use<RandomStringSource>(4, 128)
                 .Setup(p => p.PublishedAt).Use<RandomPastDateSource>()
                 .Setup(p => p.Slug).Use<RandomStringSource>(4, 128)
                 .Setup(b => b.MetaKeywords).Use<RandomStringSource>(4, 128)
                 .Setup(b => b.MetaDescription).Use<RandomStringSource>(4, 128)
                 .Setup(b => b.Author).Use<RandomStringSource>(4, 64)
                 .Setup(b => b.Body).Use<LoremIpsumSource>(5))
                 .CreateSession();
        }

        private class RandomPastDateSource : DatasourceBase<DateTime>
        {
            private readonly Random random;
            private readonly int max;
            private readonly int min;

            public RandomPastDateSource() : this(1, 5)
            {
            }

            public RandomPastDateSource(int min, int max)
            {
                this.max = max;
                this.min = min;

                random = new Random(1337);
            }

            public override DateTime Next(IGenerationSession session)
            {
                return DateTime.Now.AddYears(-random.Next(min, max));
            }
        }
    }
}